/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.auth.filter;

import com.je.auth.AuthEngine;
import com.je.auth.TokenConsts;
import com.je.auth.check.config.CheckConfig;
import com.je.auth.check.filter.AuthFilterAuthStrategy;
import com.je.auth.check.filter.AuthFilterErrorStrategy;
import com.je.auth.check.exception.BackResultException;
import com.je.auth.check.exception.StopMatchException;
import com.je.auth.check.exception.TokenException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import javax.servlet.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Servlet全局过滤器
 *
 * @author kong
 */
@Order(CheckConfig.ASSEMBLY_ORDER)
public class AuthServletFilter implements Filter {

    @Autowired
    private AuthEngine authEngine;

    // ------------------------ 设置此过滤器 拦截 & 放行 的路由

    /**
     * 拦截路由
     */
    private List<String> includeList = new ArrayList<>();

    /**
     * 放行路由
     */
    private List<String> excludeList = new ArrayList<>();

    /**
     * 添加 [拦截路由]
     *
     * @param paths 路由
     * @return 对象自身
     */
    public AuthServletFilter addInclude(String... paths) {
        includeList.addAll(Arrays.asList(paths));
        return this;
    }

    /**
     * 添加 [放行路由]
     *
     * @param paths 路由
     * @return 对象自身
     */
    public AuthServletFilter addExclude(String... paths) {
        excludeList.addAll(Arrays.asList(paths));
        return this;
    }

    /**
     * 写入 [拦截路由] 集合
     *
     * @param pathList 路由集合
     * @return 对象自身
     */
    public AuthServletFilter setIncludeList(List<String> pathList) {
        includeList = pathList;
        return this;
    }

    /**
     * 写入 [放行路由] 集合
     *
     * @param pathList 路由集合
     * @return 对象自身
     */
    public AuthServletFilter setExcludeList(List<String> pathList) {
        excludeList = pathList;
        return this;
    }

    /**
     * 获取 [拦截路由] 集合
     *
     * @return see note
     */
    public List<String> getIncludeList() {
        return includeList;
    }

    /**
     * 获取 [放行路由] 集合
     *
     * @return see note
     */
    public List<String> getExcludeList() {
        return excludeList;
    }


    // ------------------------ 钩子函数

    /**
     * 认证函数：每次请求执行
     */
    public AuthFilterAuthStrategy auth = r -> {
    };

    /**
     * 异常处理函数：每次[认证函数]发生异常时执行此函数
     */
    public AuthFilterErrorStrategy error = e -> {
        throw new TokenException(e);
    };

    /**
     * 前置函数：在每次[认证函数]之前执行
     */
    public AuthFilterAuthStrategy beforeAuth = r -> {
    };

    /**
     * 写入[认证函数]: 每次请求执行
     *
     * @param auth see note
     * @return 对象自身
     */
    public AuthServletFilter setAuth(AuthFilterAuthStrategy auth) {
        this.auth = auth;
        return this;
    }

    /**
     * 写入[异常处理函数]：每次[认证函数]发生异常时执行此函数
     *
     * @param error see note
     * @return 对象自身
     */
    public AuthServletFilter setError(AuthFilterErrorStrategy error) {
        this.error = error;
        return this;
    }

    /**
     * 写入[前置函数]：在每次[认证函数]之前执行
     *
     * @param beforeAuth see note
     * @return 对象自身
     */
    public AuthServletFilter setBeforeAuth(AuthFilterAuthStrategy beforeAuth) {
        this.beforeAuth = beforeAuth;
        return this;
    }

    // ------------------------ doFilter

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            // 执行全局过滤器
            authEngine.getAuthCheckEngine().getAuthPathChecker().match(includeList).notMatch(excludeList).check(r -> {
                beforeAuth.run(null);
                auth.run(null);
            });
        } catch (StopMatchException e) {

        } catch (Throwable e) {
            // 1. 获取异常处理策略结果
            String result = (e instanceof BackResultException) ? e.getMessage() : String.valueOf(error.run(e));

            // 2. 写入输出流
            if (response.getContentType() == null) {
                response.setContentType("text/plain; charset=utf-8");
            }
            response.getWriter().print(result);
            return;
        }

        // 执行
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }


}
